Ext.Anim = Ext.extend(Object, {
    isAnim: true,
    disableAnimations: false, // 是否禁用

    // 默认配置项
    defaultConfig: {
        from: {},                   // 动画开始时的样式
        to: {},                     // 动画结束时的样式
        duration: 250,             // 动画持续时间
        delay: 0,                  // 动画延迟时间
        easing: 'ease-in-out',   // 动画控制函数
        autoClear: true,          // 动画结束时是否清除样式
        out: true,                // 是否是离开动画（这是为特殊动画实例预留，创建进入、离开两用动画实例时才用到）
        direction: null,          // 动画方向（这是为特殊动画实例预留，创建有特定方向的动画实例时才用到）
        reverse: false            // 动画是否反向（与direction属性和opposites属性同时用）
    },

    // 反义词字典，根据reverse重置direction属性的值
    opposites: {
        'left': 'right',
        'right': 'left',
        'up': 'down',
        'down': 'up'
    },

    // 构造函数
    constructor: function(config) {
        config = Ext.apply({}, config || {}, this.defaultConfig);
        this.config = config; // config参数覆盖this.defaultConfig配置对象，赋予this.config

        Ext.Anim.superclass.constructor.call(this);

        this.running = []; // 用来记录使用此动画的dom节点
    },

    // 初始化动画与el元素的关联数据
    initConfig : function(el, runConfig) {
        var me = this,
            runtime = {},
            config = Ext.apply({}, runConfig || {}, me.config); // runConfig 覆盖 me.config

        config.el = el = Ext.get(el);

        // 如果是反向动画
        if (config.reverse && me.opposites[config.direction]) {
            config.direction = me.opposites[config.direction];
        }

        // 如果动画对象定义了before方法
        if (me.config.before) {
            me.config.before.call(config, el, config);
        }

        // 参数定义了before方法
        if (runConfig.before) {
            runConfig.before.call(config.scope || config, el, config);
        }

        return config;
    },
    
    // 动画运行方法
    run: function(el, config) {
        el = Ext.get(el);
        config = config || {};


        var me = this,
            style = el.dom.style, // 节点样式
            property,
            after = config.after;

        // 如果el正在运行这个动画
        if (me.running[el.id]) {

            // 结束el的动画运行
            me.onTransitionEnd(null, el, {
                config: config,
                after: after
            });
        }

        // 初始化动画与el元素的关联数据
        config = this.initConfig(el, config);

        // 如果禁用了动画
        if (this.disableAnimations) {

            // 遍历目标样式属性
            for (property in config.to) {
                if (!config.to.hasOwnProperty(property)) {
                    continue;
                }
                style[property] = config.to[property]; // 样式直接赋最终值
            }

            // 结束el的动画运行
            this.onTransitionEnd(null, el, {
                config: config,
                after: after
            });
            return me; //  返回
        }

        // 移除动画结束后的监听函数
        el.un('webkitTransitionEnd', me.onTransitionEnd, me);

        // 将el节点的样式设为原始状态
        style.webkitTransitionDuration = '0ms';
        for (property in config.from) {
            if (!config.from.hasOwnProperty(property)) {
                continue;
            }
            style[property] = config.from[property];
        }


        // 延时后开始动画
        setTimeout(function() {
            
            if (!el.dom) {
                return;
            }
            
            
            if (config.is3d === true) {
                el.parent().setStyle({
                    
                    '-webkit-perspective': '1200',
                    '-webkit-transform-style': 'preserve-3d'
                });
            }

            style.webkitTransitionDuration = config.duration + 'ms'; // 动画持续时间
            style.webkitTransitionProperty = 'all'; // 动画属性
            style.webkitTransitionTimingFunction = config.easing; // 动画函数

            // 注册动画结束函数
            el.on('webkitTransitionEnd', me.onTransitionEnd, me, {
                single: true,
                config: config,
                after: after
            });

            // 将el节点的样式设为目标状态
            for (property in config.to) {
                if (!config.to.hasOwnProperty(property)) {
                    continue;
                }
                style[property] = config.to[property];
            }
        }, config.delay || 5);

        // 记录el及动画配置
        me.running[el.id] = config;
        return me;
    },

    // 动画结束运行的动画
    onTransitionEnd: function(ev, el, o) {
        el = Ext.get(el);

        // 如果动画已经不在动画记录之列，可以直接跳出
        if (this.running[el.id] === undefined) {
            return;
        }

        var style = el.dom.style,
            config = o.config,
            property,
            me = this;

        // 动画结束后是否将相关样式清空
        if (config.autoClear) {
            for (property in config.to) {
                if (!config.to.hasOwnProperty(property)) {
                    continue;
                }
                style[property] = '';
            }
        }

        style.webkitTransitionDuration = null;
        style.webkitTransitionProperty = null;
        style.webkitTransitionTimingFunction = null;

        if (config.is3d) {
            el.parent().setStyle({
                '-webkit-perspective': '',
                '-webkit-transform-style': ''
            });
        }

        // 动画结束后运行的方法
        if (me.config.after) {
            me.config.after.call(config, el, config);
        }

        if (o.after) {
            o.after.call(config.scope || me, el, config);
        }

        // 移除动画记录
        delete me.running[el.id];
    }
});

Ext.Anim.seed = 1000;


Ext.Anim.run = function(el, anim, config) {

    // 如果el是组件，则取组件内的元素（Ext.Element）对象
    if (el.isComponent) {
        el = el.el;
    }

    config = config || {};

    // 如果anim是一个Ext.Anim实例对象，直接运行对象run方法
    if (anim.isAnim) {
        anim.run(el, config);
    }
    else {

        // 如果anim是一个配置对象
        if (Ext.isObject(anim)) {

            // anim.before和config.before同时存在，则anim.before作为config.before的拦截器，
            // 即anim.before先运行，返回值为真值才会运行config.before。这个过程封装在一个新
            // 方法内并赋给config.before
            if (config.before && anim.before) {
                config.before = Ext.createInterceptor(config.before, anim.before, anim.scope);
            }

            // anim.after和config.after同时存在，则anim.after作为config.after的拦截器，
            // 即anim.after先运行，返回值为真值才会运行config.after。这个过程封装在一个新
            // 方法内并赋给config.after
            if (config.after && anim.after) {
                config.after = Ext.createInterceptor(config.after, anim.after, anim.scope);
            }

            // 以config覆盖anim的形式混合成一个新配置对象
            config = Ext.apply({}, config, anim);

            // anim用事先定义好的动画名
            anim = anim.type;
        }

        // 如果没有事先创建的Ext.Anim实例，抛出异常
        if (!Ext.anims[anim]) {
            throw anim + ' is not a valid animation type.';
        }
        else {
            
            if (el && el.dom) {
                Ext.anims[anim].run(el, config); // 运行Ext.Anim实例
            }
        }
    }
};